{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Introduction to the Planner\n",
    "\n",
    "The Planner is one of the fundamental concepts of the Semantic Kernel. It makes use of the collection of skills that have been registered to the kernel and using AI, will formulate a plan to execute a given ask.\n",
    "\n",
    "Read more about it [here](https://aka.ms/sk/concepts/planner)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [],
   "source": [
    "#r \"nuget: Microsoft.SemanticKernel, 0.12.207.1-preview\"\n",
    "\n",
    "#!import config/Settings.cs\n",
    "\n",
    "using Microsoft.SemanticKernel;\n",
    "using Microsoft.SemanticKernel.CoreSkills;\n",
    "using Microsoft.SemanticKernel.KernelExtensions;\n",
    "using Microsoft.SemanticKernel.Orchestration;\n",
    "\n",
    "IKernel kernel = KernelBuilder.Create();\n",
    "\n",
    "// Configure AI backend used by the kernel\n",
    "var (useAzureOpenAI, model, azureEndpoint, apiKey, orgId) = Settings.LoadFromFile();\n",
    "if (useAzureOpenAI)\n",
    "    kernel.Config.AddAzureTextCompletionService(\"davinci\", model, azureEndpoint, apiKey);\n",
    "else\n",
    "    kernel.Config.AddOpenAITextCompletionService(\"davinci\", model, apiKey, orgId);"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Setting Up the Planner\n",
    "The planner is located in the Semantic Kernel's CoreSkills and requires Orchestration"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [],
   "source": [
    "// Load native skill into the kernel registry, sharing its functions with prompt templates\n",
    "var planner = kernel.ImportSkill(new PlannerSkill(kernel));"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Providing skills to the planner\n",
    "The planner needs to know what skills are available to it. Here we'll give it access to the `SummarizeSkill` and `WriterSkill` we have defined on disk."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [],
   "source": [
    "var skillsDirectory = Path.Combine(System.IO.Directory.GetCurrentDirectory(), \"..\", \"..\", \"skills\");\n",
    "kernel.ImportSemanticSkillFromDirectory(skillsDirectory, \"SummarizeSkill\");\n",
    "kernel.ImportSemanticSkillFromDirectory(skillsDirectory, \"WriterSkill\");"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Define your ASK. What do you want the Kernel to do?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Original plan:\n",
      "\n",
      "<goal>\n",
      "Tomorrow is Valentine's day. I need to come up with a few date ideas and e-mail them to my significant other.\n",
      "</goal>\n",
      "<plan>\n",
      "  <function.WriterSkill.Brainstorm input=\"Valentine's Day Date Ideas\" setContextVariable=\"DATE_IDEAS\"/>\n",
      "  <function._GLOBAL_FUNCTIONS_.BucketOutputs input=\"$DATE_IDEAS\" bucketCount=\"3\" bucketLabelPrefix=\"DATE_IDEA\"/>\n",
      "  <function.WriterSkill.EmailTo to=\"My Significant Other\" input=\"$DATE_IDEA_1;$DATE_IDEA_2;$DATE_IDEA_3\" sender=\"Me\" />\n",
      "</plan>\n"
     ]
    }
   ],
   "source": [
    "var ask = \"Tomorrow is Valentine's day. I need to come up with a few date ideas and e-mail them to my significant other.\";\n",
    "var originalPlan = await kernel.RunAsync(ask, planner[\"CreatePlan\"]);\n",
    "\n",
    "Console.WriteLine(\"Original plan:\\n\");\n",
    "Console.WriteLine(originalPlan.Variables.ToPlan().PlanString);"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As you can see in the above plan, the Planner has taken the user's ask and converted it into an XML-based plan detailing how the AI would go about solving this task.\n",
    "\n",
    "It makes use of the skills that the Kernel has available to it and determines which functions to call in order to fullfill the user's ask.\n",
    "\n",
    "The output of each step of the plan gets set as `setContextVariable` which makes it available as `input` to the next skill."
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's also define an inline skill and have it be available to the Planner.\n",
    "Be sure to give it a function name and skill name."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [],
   "source": [
    "string skPrompt = \"\"\"\n",
    "{{$input}}\n",
    "\n",
    "Rewrite the above in the style of Shakespeare.\n",
    "\"\"\";\n",
    "var shakespeareFunction = kernel.CreateSemanticFunction(skPrompt, \"shakespeare\", \"ShakespeareSkill\", maxTokens: 2000, temperature: 0.2, topP: 0.5);"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's update our ask using this new skill."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [],
   "source": [
    "var ask = @\"Tomorrow is Valentine's day. I need to come up with a few date ideas.\n",
    " She likes Shakespeare so write using his style. E-mail these ideas to my significant other\";"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [],
   "source": [
    "var newPlan = await kernel.RunAsync(ask, planner[\"CreatePlan\"]);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Updated plan:\n",
      "\n",
      "<goal>\n",
      "Tomorrow is Valentine's day. I need to come up with a few date ideas.\n",
      " She likes Shakespeare so write using his style. E-mail these ideas to my significant other\n",
      "</goal>\n",
      "<plan>\n",
      "  <function.WriterSkill.Brainstorm input=\"Valentine's Day Date Ideas\" setContextVariable=\"IDEAS\"/>\n",
      "  <function.ShakespeareSkill.shakespeare input=\"$IDEAS\" setContextVariable=\"SHAKESPEARE_IDEAS\"/>\n",
      "  <function.WriterSkill.EmailTo to=\"My Significant Other\" input=\"$SHAKESPEARE_IDEAS\" sender=\"Me\" appendToResult=\"RESULT__EMAIL\"/>\n",
      "</plan>\n"
     ]
    }
   ],
   "source": [
    "Console.WriteLine(\"Updated plan:\\n\");\n",
    "Console.WriteLine(newPlan.Variables.ToPlan().PlanString);"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Executing the plan\n",
    "\n",
    "Now that we have a plan, let's try to execute it! The Planner has a skill called `ExecutePlan`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [],
   "source": [
    "var executionResults = newPlan;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Step 1 - Execution results:\n",
      "\n",
      "<goal>\n",
      "Tomorrow is Valentine's day. I need to come up with a few date ideas.\n",
      " She likes Shakespeare so write using his style. E-mail these ideas to my significant other\n",
      "</goal><plan>\n",
      "  <function.ShakespeareSkill.shakespeare input=\"$IDEAS\" setContextVariable=\"SHAKESPEARE_IDEAS\" />\n",
      "  <function.WriterSkill.EmailTo to=\"My Significant Other\" input=\"$SHAKESPEARE_IDEAS\" sender=\"Me\" appendToResult=\"RESULT__EMAIL\" />\n",
      "</plan>\n",
      "\n",
      "Step 2 - Execution results:\n",
      "\n",
      "<goal>\n",
      "Tomorrow is Valentine's day. I need to come up with a few date ideas.\n",
      " She likes Shakespeare so write using his style. E-mail these ideas to my significant other\n",
      "</goal><plan>\n",
      "  <function.WriterSkill.EmailTo to=\"My Significant Other\" input=\"$SHAKESPEARE_IDEAS\" sender=\"Me\" appendToResult=\"RESULT__EMAIL\" />\n",
      "</plan>\n",
      "\n",
      "Step 3 - Execution results:\n",
      "\n",
      "<goal>\n",
      "Tomorrow is Valentine's day. I need to come up with a few date ideas.\n",
      " She likes Shakespeare so write using his style. E-mail these ideas to my significant other\n",
      "</goal><plan>\n",
      "</plan>\n",
      "Step 3 - COMPLETE!\n",
      "RESULT__EMAIL\n",
      "\n",
      "\n",
      "Dear My Significant Other,\n",
      "\n",
      "I hope you're doing well. I wanted to suggest some fun activities that we can do together. \n",
      "\n",
      "1. Let's cook a dinner of love's delight.\n",
      "2. How about a picnic in the park?\n",
      "3. We can take a romantic walk in the moonlight.\n",
      "4. Let's go to a drive-in movie.\n",
      "5. Visiting a museum or art gallery would be great.\n",
      "6. We can have a game night.\n",
      "7. Going to a concert would be fun.\n",
      "8. Let's take a hot air balloon ride.\n",
      "9. We can visit a local winery.\n",
      "10. Let's have a spa day.\n",
      "\n",
      "I'm looking forward to spending time with you.\n",
      "\n",
      "Thanks,\n",
      "Me\n"
     ]
    }
   ],
   "source": [
    "int step = 1;\n",
    "int maxSteps = 10;\n",
    "while (!executionResults.Variables.ToPlan().IsComplete && step < maxSteps)\n",
    "{\n",
    "    var results = await kernel.RunAsync(executionResults.Variables, planner[\"ExecutePlan\"]);\n",
    "    if (results.Variables.ToPlan().IsSuccessful)\n",
    "    {\n",
    "        Console.WriteLine($\"Step {step} - Execution results:\\n\");\n",
    "        Console.WriteLine(results.Variables.ToPlan().PlanString);\n",
    "\n",
    "        if (results.Variables.ToPlan().IsComplete)\n",
    "        {\n",
    "            Console.WriteLine($\"Step {step} - COMPLETE!\");\n",
    "            Console.WriteLine(results.Variables.ToPlan().Result);\n",
    "            break;\n",
    "        }\n",
    "    }\n",
    "    else\n",
    "    {\n",
    "        Console.WriteLine($\"Step {step} - Execution failed:\");\n",
    "        Console.WriteLine(results.Variables.ToPlan().Result);\n",
    "        break;\n",
    "    }\n",
    "    \n",
    "    executionResults = results;\n",
    "    step++;\n",
    "    Console.WriteLine(\"\");\n",
    "}"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".NET (C#)",
   "language": "C#",
   "name": ".net-csharp"
  },
  "language_info": {
   "name": "polyglot-notebook"
  },
  "polyglot_notebook": {
   "kernelInfo": {
    "defaultKernelName": "csharp",
    "items": [
     {
      "aliases": [],
      "name": "csharp"
     }
    ]
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
